<div class="media-alt-editor {className}">
  <textarea
    id="the-media-alt-input-{realm}-{index}"
    class="media-alt-input"
    placeholder="{intl.altLabel}"
    ref:textarea
    bind:value=rawText
  ></textarea>
  <label for="the-media-alt-input-{realm}-{index}" class="sr-only">
    {intl.altLabel}
  </label>
  <LengthGauge
    {length}
    {overLimit}
    max={mediaAltCharLimit}
  />
  <LengthIndicator
    {length}
    {overLimit}
    max={mediaAltCharLimit}
    style="width: 100%; text-align: right;"
  />
  <button class="extract-text-button" type="button"
          on:click="onClick()"
          disabled={extracting}
          aria-label={extractButtonLabel}
  >
    <SvgIcon href="{extracting ? '#fa-spinner' : '#fa-magic'}"
             className="extract-text-svg {extracting ? 'spin' : ''}"
    />
    <span>{extractButtonText}</span>
  </button>
  <LengthGauge
    length={extractionProgress}
    overLimit={false}
    max={100}
  />
</div>
<style>
  .media-alt-editor {
    display: flex;
    flex-direction: column;
  }
  .media-alt-input {
    padding: 5px;
    border: 1px solid var(--input-border);
    min-height: 40px;
    resize: none;
    overflow: hidden;
    word-wrap: break-word;
    /* Text must be at least 16px or else iOS Safari zooms in */
    font-size: 1.2em;
    max-height: 70vh;
  }

  .extract-text-button {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 10px;
  }

  .extract-text-button span {
    margin-left: 15px;
  }

  :global(.extract-text-svg) {
    fill: var(--button-text);
    width: 18px;
    height: 18px;
  }

  @media (max-height: 767px) {
    .media-alt-input {
      max-height: 40vh;
      width: 100%;
      overflow: auto;
    }
    .extract-text-button {
      margin-top: 0;
    }
    button.extract-text-button {
      padding: 7px 10px;
    }
  }

  @media (min-height: 768px) {
    .media-alt-input {
      min-width: 250px;
      min-height: 75px;
    }
  }
</style>
<script>
  import { requestPostAnimationFrame } from '../../../_utils/requestPostAnimationFrame.js'
  import { mark, stop } from '../../../_utils/marks.js'
  import { autosize } from '../../../_thirdparty/autosize/autosize.js'
  import { observe } from 'svelte-extras'
  import { throttleTimer } from '../../../_utils/throttleTimer.js'
  import { get } from '../../../_utils/lodash-lite.js'
  import { store } from '../../../_store/store.js'
  import { MEDIA_ALT_CHAR_LIMIT } from '../../../_static/media.js'
  import LengthGauge from '../../LengthGauge.html'
  import LengthIndicator from '../../LengthIndicator.html'
  import { length } from 'stringz'
  import { runTesseract } from '../../../_utils/runTesseract.js'
  import SvgIcon from '../../SvgIcon.html'
  import { toast } from '../../toast/toast.js'
  import { formatIntl } from '../../../_utils/formatIntl.js'
  import { database } from '../../../_database/database.js'

  const updateRawTextInStore = throttleTimer(requestPostAnimationFrame)

  export default {
    oncreate () {
      this.setupAutosize()
      this.setupSyncFromStore()
      this.setupSyncToStore()
    },
    ondestroy () {
      this.teardownAutosize()
    },
    store: () => store,
    data: () => ({
      rawText: '',
      mediaAltCharLimit: MEDIA_ALT_CHAR_LIMIT,
      extracting: false,
      className: '',
      extractionProgress: 0
    }),
    computed: {
      length: ({ rawText }) => length(rawText || ''),
      overLimit: ({ mediaAltCharLimit, length }) => length > mediaAltCharLimit,
      url: ({ media, index }) => get(media, [index, 'data', 'url']),
      mediaId: ({ media, index }) => get(media, [index, 'data', 'id']),
      extractButtonText: ({ extracting }) => extracting ? 'intl.extractingText' : 'intl.extractText',
      extractButtonLabel: ({ extractButtonText, extractionProgress, extracting }) => {
        if (extracting) {
          return formatIntl('intl.extractingTextCompletion', { percent: Math.round(extractionProgress) })
        }
        return extractButtonText
      }
    },
    methods: {
      observe,
      setupSyncFromStore () {
        this.observe('media', media => {
          media = media || []
          const { index, rawText } = this.get()
          const text = get(media, [index, 'description'], '')
          if (rawText !== text) {
            this.set({ rawText: text })
          }
        })
      },
      setupSyncToStore () {
        this.observe('rawText', rawText => {
          updateRawTextInStore(() => {
            const { realm, index, media } = this.get()
            if (media[index].description !== rawText) {
              media[index].description = rawText
              this.store.setComposeData(realm, { media })
              this.store.save()
            }
            this.fire('resize')
          })
        }, { init: false })
      },
      setupAutosize () {
        const textarea = this.refs.textarea
        requestPostAnimationFrame(() => {
          mark('autosize()')
          autosize(textarea)
          stop('autosize()')
        })
      },
      teardownAutosize () {
        mark('autosize.destroy()')
        autosize.destroy(this.refs.textarea)
        stop('autosize.destroy()')
      },
      measure () {
        autosize.update(this.refs.textarea)
      },
      async onClick () {
        this.set({ extracting: true })
        try {
          const { url, mediaId } = this.get()
          const onProgress = progress => {
            requestAnimationFrame(() => {
              this.set({ extractionProgress: progress * 100 })
            })
          }
          const file = await database.getCachedMediaFile(mediaId)
          let text
          if (file) { // Avoid downloading from the network a file that the user *just* uploaded
            const fileUrl = URL.createObjectURL(file)
            try {
              text = await runTesseract(fileUrl, onProgress)
            } finally {
              URL.revokeObjectURL(fileUrl)
            }
          } else {
            text = await runTesseract(url, onProgress)
          }
          const { media, index, realm } = this.get()
          if (media[index].description !== text) {
            media[index].description = text
            this.store.setComposeData(realm, { media })
            this.store.save()
          }
        } catch (err) {
          console.error(err)
          /* no await */ toast.say('intl.unableToExtractText')
        } finally {
          this.set({ extracting: false })
          setTimeout(() => {
            requestAnimationFrame(() => {
              this.set({ extractionProgress: 0 })
            })
          }, 400)
        }
      }
    },
    components: {
      LengthGauge,
      LengthIndicator,
      SvgIcon
    }
  }
</script>
